/**
 * OSAmI: Open Source Ambient Intelligence
 * Copyright (C) 2010 UJF.
 * Contact: osami-general@osami-commons.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */

package org.osami.gateway.mediator.sensedata.internal;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import fr.liglab.adele.cilia.Data;
import fr.liglab.adele.cilia.framework.IProcessor;
import org.osami.gateway.sensor.data.SenseData;
import org.osgi.service.log.LogService;

import static org.osami.gateway.sensor.data.SenseData.DEFAULT_DATA_KEY;

public class SenseDataAggregator implements IProcessor {

	// TODO replace with a global variable.
	private static final String GATEWAY_ID = "B1-163";


	private final String AVERAGE_VALUE_KEY = "average-value";

	private final String AVERAGE_TYPE_KEY = "average-type";
	
	private final String AVERAGE_LOCATION_KEY = "average-location";
	/**
	 * Logger, injected by iPOJO.
	 */
	private LogService logger;

	/**
	 * Return the aggregated SenseData objects to the drools working memory.
	 */
	public List process(List dataset) {
		List resultSet = new ArrayList();
		// Group by type of Sensedata
		Map<String, List<SenseData>> typeGroups = new HashMap<String, List<SenseData>>();
		while (!dataset.isEmpty()) {
			String type = ((SenseData) ((Data) dataset.get(0)).getProperty(SenseData.DEFAULT_DATA_KEY)).getType();
			List<SenseData> subdataset = new LinkedList<SenseData>();
			for (Iterator iterator = dataset.iterator(); iterator.hasNext();) {
				Data raw = (Data) iterator.next();
				SenseData data = (SenseData) raw.getProperty(SenseData.DEFAULT_DATA_KEY);
				if (type.equals(data.getType())) {
					subdataset.add(data);
					iterator.remove();
				}
			}
			typeGroups.put(type, subdataset);
		}
		
		
		for (String type : typeGroups.keySet()) {
			dataset=typeGroups.get(type);
			// Group by senseId of SenseData
			Map<String, List<SenseData>> idGroups = new HashMap<String, List<SenseData>>();
			while (!dataset.isEmpty()) {
				String senseId = ((SenseData)dataset.get(0)).getSenseId();
				List<SenseData> subdataset = new LinkedList<SenseData>();
				for (Iterator iterator = dataset.iterator(); iterator.hasNext();) {
					SenseData data = (SenseData) iterator.next();
					if (senseId.equals(data.getSenseId())) {
						subdataset.add(data);
						iterator.remove();
					}
				}
				idGroups.put(senseId, subdataset);
			}
			
			// Compute the average for each group
			// TODO check the unit and convert if needed
			for (String senseId : idGroups.keySet()) {
				Iterator<SenseData> i = idGroups.get(senseId).iterator();
				double count = (double) idGroups.get(senseId).size();
				double average = 0;
				// TODO Check unit conversion here
				String currentUnit = idGroups.get(senseId).get(0).getUnit();
				// Location info
				String location = idGroups.get(senseId).get(0).getLocation();
				
				while (i.hasNext()) {
					SenseData data = (SenseData) i.next();
					try {
						average += data.getValue();
					} catch (NullPointerException ne) {
						logger.log(LogService.LOG_WARNING,"The property of key: " + DEFAULT_DATA_KEY+ " does not exist, bad data", ne);
					} catch (ClassCastException ce) {
						logger.log(
								LogService.LOG_WARNING,"The property of key: "+ DEFAULT_DATA_KEY+ " is not a valid SenseData object, bad data",ce);
					}
				}
				average /= count;
				Dictionary<String, Object> meta = new Hashtable<String, Object>();
				meta.put(Data.DATA_TIMESTAMP, System.currentTimeMillis());
				meta.put(AVERAGE_LOCATION_KEY, location);
				meta.put(AVERAGE_VALUE_KEY, average);
				meta.put(AVERAGE_TYPE_KEY, type);
				resultSet.add(new Data(null,null,meta));
			}
		}
		
		return resultSet;
	}
}
